#include "qworld.h"
#include "qgame.h"
#include "adddialog.h"
#include "configdialog.h"
#include "qworldscene.h"
#include "qstatistic.h"
#include "qlifetable.h"
#include "qworldview.h"

#include <QtGui>
#include <QGLWidget>
#include <QtScript>

/**
 * @author Stefan Weigert <stefan.weigert@mailbox.tu-dresden.de>
 */

QWorld::QWorld() : QMainWindow()
{
	QSplashScreen splash ( QPixmap ( "src/images/splash.png" ) );
	splash.finish ( this );
	splash.show();

	setDockNestingEnabled(false);
	setDockOptions( AllowTabbedDocks | VerticalTabs | AnimatedDocks );

	// canvas
	splash.showMessage ( "Creating Canvas..." );
	//sleep(1);
	printf ( "Creating Canvas..." );

	scene = new QWorldScene ( 700, 450, this );
	worldView = new QWorldView ( scene );
	worldView -> setDragMode ( QGraphicsView::ScrollHandDrag );
	worldView -> setResizeScene ( false );

	printf ( "done.\n" );


	// statistics
	splash.showMessage ( "Creating Statistics..." );
	//sleep(1);
	printf ( "Creating Statistics..." );

	// life statistics
	lifeStat = new QStatistic ( 780, 175, this );
	lifeStatisticView = new QWorldView ( lifeStat );
	lifeStatisticView -> setDragMode ( QGraphicsView::ScrollHandDrag );
	lifeStatisticView -> setResizeScene ( true );

	// dna statistics
	dnaStat = new QStatistic ( 780, 175, this );
	dnaStatisticView = new QWorldView ( dnaStat );
	dnaStatisticView -> setDragMode ( QGraphicsView::ScrollHandDrag );
	dnaStatisticView -> setResizeScene ( true );

	lifeStatDock = new QDockWidget ( tr ( "Life" ), this );
	lifeStatDock -> setWidget ( lifeStatisticView );
	lifeStatDock -> adjustSize();
//	lifeStatDock -> hide();
	addDockWidget ( Qt::BottomDockWidgetArea, lifeStatDock, Qt::Horizontal );

	dnaStatDock = new QDockWidget ( tr ( "Dna" ), this );
	dnaStatDock -> setWidget ( dnaStatisticView );
	dnaStatDock -> adjustSize();
//	dnaStatDock -> hide();
	addDockWidget ( Qt::BottomDockWidgetArea, dnaStatDock, Qt::Horizontal );

	printf ( "done.\n" );

	// config
	splash.showMessage ( "Creating Config..." );
	printf ( "Creating Config..." );

	QVBoxLayout* layout = new QVBoxLayout();

	layout -> addWidget( new QLabel ( tr ( "Additional Delay per Update:" ) ) );
	lifeUpdateIntervalSpin = new QSpinBox ( );
	lifeUpdateIntervalSpin -> setRange ( 1, 1000000 );
	lifeUpdateIntervalSpin -> setSuffix ( " ms" );
	lifeUpdateIntervalSpin -> setValue ( 50 );
	layout -> addWidget( lifeUpdateIntervalSpin );

	layout -> addSpacing(20);

	layout -> addWidget( new QLabel ( tr ( "Statistics Update Ratio:" ) ) );
	statUpdateRatioSpin = new QSpinBox ( );
	statUpdateRatioSpin -> setRange ( 1, 1000000 );
	statUpdateRatioSpin -> setSuffix ( " / 1" );
	statUpdateRatioSpin -> setValue ( 1 );
	layout -> addWidget( statUpdateRatioSpin );

	layout -> addSpacing(20);

	layout -> addWidget( new QLabel ( tr ( "Scene Update Ratio:" ) ) );
	sceneUpdateRatioSpin = new QSpinBox ( );
	sceneUpdateRatioSpin -> setRange ( 1, 1000000 );
	sceneUpdateRatioSpin -> setSuffix ( " / 1" );
	sceneUpdateRatioSpin -> setValue ( 1 );
	layout -> addWidget( sceneUpdateRatioSpin );

	layout -> addStretch( );

	QWidget* cont = new QWidget(this);
	cont -> setLayout(layout);

	configDock = new QDockWidget ( tr ( "Config" ), this );
	configDock -> setWidget ( cont );
	configDock -> adjustSize();
//	configDock -> hide();
	addDockWidget ( Qt::LeftDockWidgetArea, configDock, Qt::Vertical );

	printf ( "done.\n" );


	// details table
	splash.showMessage ( "Creating Details View..." );
	//sleep(1);
	printf ( "Creating Details View..." );

	detailsTable = new QLifeTable ( this );

	detailsDock = new QDockWidget ( tr ( "Details" ), this );
	detailsDock -> setWidget ( detailsTable );
	detailsDock -> adjustSize();
//	detailsDock -> hide();
	addDockWidget ( Qt::LeftDockWidgetArea, detailsDock, Qt::Vertical );

	printf ( "done.\n" );


	// dialogs
	splash.showMessage ( "Creating Dialogs..." );
	printf ( "Creating Dialogs..." );

	// add dialog
	QStringList lifeList;
	lifeList << "Animal" << "Gravity";
	addDlg = new AddDialog ( lifeList, this );
	connect ( addDlg, SIGNAL ( accepted() ), this, SLOT ( addAccepted() ) );

	// config dialog
	confDlg = new ConfigDialog ( this );
	connect ( confDlg, SIGNAL ( accepted() ), this, SLOT ( confAccepted() ) );

	printf ( "done.\n" );


	// game
	splash.showMessage ( "Creating Kernel..." );
	printf ( "Creating Kernel..." );

	game = new QGame ( this, 700, 450 );
	game -> setScene ( scene );
	game -> setLifeStatistic ( lifeStat );
	game -> setDnaStatistic ( dnaStat );
	connect ( statUpdateRatioSpin,
		SIGNAL ( valueChanged ( int ) ),
		( QObject* ) game,
		SLOT ( changeStatUpdateRatio ( int ) ) );
	connect ( sceneUpdateRatioSpin,
		SIGNAL ( valueChanged ( int ) ),
		( QObject* ) game,
		SLOT ( changeSceneUpdateRatio ( int ) ) );
	connect ( lifeUpdateIntervalSpin,
		SIGNAL ( valueChanged ( int ) ),
		( QObject* ) game,
		SLOT ( changeLifeUpdateInterval ( int ) ) );

	printf ( "done.\n" );


	// actions
	splash.showMessage ( "Configuring Actions..." );
	printf ( "Configuring Actions..." );

	createActions();
	createMenus();
	createToolBar();

	printf ( "done.\n" );

	setCentralWidget ( worldView );
	setWindowTitle ( tr ( "QWorld" ) );

	resize ( 800, 600 );
}

QLifeTable* QWorld::getLifeTable()
{
	return detailsTable;
}

void QWorld::createActions()
{
	newAction = new QAction ( QIcon ( "src/images/filenew.png" ), tr ( "&New Game" ), this );
	newAction -> setShortcut ( tr ( "Ctrl+n" ) );
	connect ( newAction, SIGNAL ( triggered() ), this, SLOT ( newGame() ) );

	exitAction = new QAction ( tr ( "&Quit" ), this );
	exitAction -> setShortcut ( tr ( "q" ) );
	connect ( exitAction, SIGNAL ( triggered() ), this, SLOT ( quit() ) );

	logLifeAction = new QAction ( tr ( "Lo&g Life" ), this );
	logLifeAction -> setShortcut ( tr ( "Ctrl+G" ) );
	logLifeAction -> setCheckable ( true );
	logLifeAction -> setChecked ( false );
	connect ( logLifeAction, SIGNAL ( triggered() ), this, SLOT ( logLife() ) );

	logDnaAction = new QAction ( tr ( "Log &Dna" ), this );
	logDnaAction -> setShortcut ( tr ( "Ctrl+D" ) );
	logDnaAction -> setCheckable ( true );
	logDnaAction -> setChecked ( false );
	connect ( logDnaAction, SIGNAL ( triggered() ), this, SLOT ( logDna() ) );

	addAction = new QAction ( QIcon ( "src/images/add.png" ), tr ( "A&dd..." ), this );
	connect ( addAction, SIGNAL ( triggered() ), this, SLOT ( add() ) );

	addAnimalAction = new QAction ( QIcon ( "src/images/add_animal.png" ), tr ( "Add &Animal" ), this );
	addAnimalAction -> setShortcut ( tr ( "a" ) );
	connect ( addAnimalAction, SIGNAL ( triggered() ), this, SLOT ( addAnimal() ) );

	addGravityAction = new QAction ( QIcon ( "src/images/add_gravity.png" ), tr ( "Add &Gravity" ), this );
	addGravityAction -> setShortcut ( tr ( "g" ) );
	connect ( addGravityAction, SIGNAL ( triggered() ), this, SLOT ( addGravity() ) );

	startAction = new QAction ( QIcon ( "src/images/player_play.png" ), tr ( "&Start" ), this );
	startAction -> setShortcut ( tr ( "s" ) );
	connect ( startAction, SIGNAL ( triggered() ), this, SLOT ( startGame() ) );

	stopAction = new QAction ( QIcon ( "src/images/player_stop.png" ), tr ( "Sto&p" ), this );
	stopAction -> setShortcut ( tr ( "p" ) );
	connect ( stopAction, SIGNAL ( triggered() ), this, SLOT ( stopGame() ) );

	drawOpenGLAction = new QAction ( tr ( "Draw using &OpenGL" ), this );
	drawOpenGLAction -> setShortcut ( tr ( "Ctrl+O" ) );
	drawOpenGLAction -> setCheckable ( true );
	drawOpenGLAction -> setChecked ( false );
	connect ( drawOpenGLAction, SIGNAL ( triggered() ), this, SLOT ( drawOpenGL() ) );

	drawLinesAction = new QAction ( tr ( "Draw &Lines to Destination" ), this );
	drawLinesAction -> setShortcut ( tr ( "Ctrl+L" ) );
	drawLinesAction -> setCheckable ( true );
	drawLinesAction -> setChecked ( false );
	connect ( drawLinesAction, SIGNAL ( triggered() ), this, SLOT ( drawLines() ) );

	drawCirclesAction = new QAction ( tr ( "Draw &View Distance" ), this );
	drawCirclesAction -> setShortcut ( tr ( "Ctrl+V" ) );
	drawCirclesAction -> setCheckable ( true );
	drawCirclesAction -> setChecked ( false );
	connect ( drawCirclesAction, SIGNAL ( triggered() ), this, SLOT ( drawCircles() ) );

	antialiasAction = new QAction ( tr ( "Use &Antialiasing" ), this );
	antialiasAction -> setShortcut ( tr ( "Ctrl+A" ) );
	antialiasAction -> setCheckable ( true );
	antialiasAction -> setChecked ( false );
	connect ( antialiasAction, SIGNAL ( triggered() ), this, SLOT ( drawAntialiased() ) );

	showDetailsAction = detailsDock -> toggleViewAction();
	showLifeStatAction = lifeStatDock -> toggleViewAction();
	showDnaStatAction = dnaStatDock -> toggleViewAction();
//	showWorldAction = worldDock -> toggleViewAction();
	showConfigAction = configDock -> toggleViewAction();
}

void QWorld::createMenus()
{
	QMenu* gameMenu = menuBar() -> addMenu ( tr ( "&Game" ) );
	gameMenu -> addAction ( newAction );
	gameMenu -> addSeparator();
	gameMenu -> addAction ( exitAction );

	QMenu* controlMenu = menuBar() -> addMenu ( tr ( "&Control" ) );
	controlMenu -> addAction ( logLifeAction );
	controlMenu -> addAction ( logDnaAction );
	controlMenu -> addSeparator();
	controlMenu -> addAction ( addAction );
	controlMenu -> addAction ( addAnimalAction );
	controlMenu -> addAction ( addGravityAction );
	controlMenu -> addSeparator();
	controlMenu -> addAction ( startAction );
	controlMenu -> addAction ( stopAction );

	QMenu* viewMenu = menuBar() -> addMenu ( tr ( "&View" ) );
//	viewMenu -> addAction ( showWorldAction );
	viewMenu -> addAction ( showDetailsAction );
	viewMenu -> addAction ( showLifeStatAction );
	viewMenu -> addAction ( showDnaStatAction );
	viewMenu -> addAction ( showConfigAction );
	viewMenu -> addSeparator();
	viewMenu -> addAction ( drawLinesAction );
	viewMenu -> addAction ( drawCirclesAction );
	viewMenu -> addSeparator();
	viewMenu -> addAction ( antialiasAction );
	viewMenu -> addAction ( drawOpenGLAction );
}

void QWorld::createToolBar()
{
	QToolBar* gameToolBar = new QToolBar ( tr ( "Game" ), this );
	gameToolBar -> addAction ( newAction );

	QToolBar* ctrlToolBar = new QToolBar ( tr ( "Controls" ), this );
	ctrlToolBar -> addAction ( addAction );
	ctrlToolBar -> addAction ( addAnimalAction );
	ctrlToolBar -> addAction ( addGravityAction );
	ctrlToolBar -> addSeparator();
	ctrlToolBar -> addAction ( startAction );
	ctrlToolBar -> addAction ( stopAction );

/*	QToolBar* viewToolBar = new QToolBar ( tr ( "View" ), this );
	viewToolBar -> setOrientation(Qt::Vertical);
//	viewToolBar -> addAction ( showWorldAction );
	viewToolBar -> addAction ( showDetailsAction );
	viewToolBar -> addAction ( showConfigAction );

	QToolBar* statViewToolBar = new QToolBar( tr ( "Statistics" ), this );
	statViewToolBar -> addAction ( showLifeStatAction );
	statViewToolBar -> addAction ( showDnaStatAction );*/

	addToolBar ( Qt::TopToolBarArea, gameToolBar );
	addToolBar ( Qt::TopToolBarArea, ctrlToolBar );
/*	addToolBar ( Qt::LeftToolBarArea, viewToolBar );
	addToolBar ( Qt::BottomToolBarArea, statViewToolBar);*/
}

void QWorld::newGame()
{
	game -> reset();

	confDlg -> show();
}

void QWorld::quit()
{
	newGame();
	exit ( 0 );
}

void QWorld::addAccepted()
{
	if ( ( addDlg -> getLife() ) == "Animal" )
	{
		for ( int i = 0; i < addDlg -> getNumber(); ++i ) game -> addQAnimalProto ( addDlg -> getColor() );
	}
	else if ( ( addDlg -> getLife() ) == "Gravity" )
	{
		for ( int i = 0; i < addDlg -> getNumber(); ++i ) game -> addQGravityProto ( addDlg -> getColor() );
	}
}

void QWorld::confAccepted()
{
	width = confDlg -> getWidth();
	height = confDlg -> getHeight();

	scene -> setDimension ( width, height );
	game -> setDimension ( width, height );
}

void QWorld::logLife()
{
	game -> logLifeStatistics ( logLifeAction -> isChecked() );
}

void QWorld::logDna()
{
	game -> logDnaStatistics ( logDnaAction -> isChecked() );
}

void QWorld::add()
{
	addDlg -> show();
}

void QWorld::addAnimal()
{
	game -> addQAnimalProto ( Qt::red );
}

void QWorld::addGravity()
{
	game -> addQGravityProto ( Qt::green );
}

void QWorld::drawOpenGL()
{
	if ( drawOpenGLAction -> isChecked() )
	{
		QGLFormat format;
/*		format.setAlpha(true);
		format.setStereo(true);
		format.setDoubleBuffer(true);
		format.setOverlay(true);
		format.setSampleBuffers(true);
		format.setSamples(2);
		format.setStencil(true);*/
		worldView -> setViewport ( new QGLWidget ( format, worldView ) );
		lifeStatisticView -> setViewport ( new QGLWidget ( format, lifeStatisticView ) );
		dnaStatisticView -> setViewport ( new QGLWidget ( format, dnaStatisticView ) );
	}
	else
	{
		worldView -> setViewport ( new QWidget ( worldView ) );
		lifeStatisticView -> setViewport ( new QWidget ( lifeStatisticView ) );
		dnaStatisticView -> setViewport ( new QWidget ( dnaStatisticView ) );
	}
}

void QWorld::drawLines()
{
	scene -> drawLines ( drawLinesAction -> isChecked() );
}

void QWorld::drawCircles()
{
	scene -> drawCircles ( drawCirclesAction -> isChecked() );
}

void QWorld::drawAntialiased()
{
	worldView -> setRenderHint ( QPainter::Antialiasing, antialiasAction -> isChecked() );
	lifeStatisticView -> setRenderHint ( QPainter::Antialiasing, antialiasAction -> isChecked() );
	dnaStatisticView -> setRenderHint ( QPainter::Antialiasing, antialiasAction -> isChecked() );
}

void QWorld::startGame()
{
	game -> start();
	startAction -> setIcon ( QIcon ( "src/images/player_pause.png" ) );
	startAction -> setText ( tr ( "Pau&se" ) );
	disconnect ( startAction, SIGNAL ( triggered() ), this, SLOT ( startGame() ) );
	connect ( startAction, SIGNAL ( triggered() ), this, SLOT ( pauseGame() ) );
}

void QWorld::pauseGame()
{
	game -> pause();
	startAction -> setText ( tr ( "&Start" ) );
	startAction -> setIcon ( QIcon ( "src/images/player_play.png" ) );
	disconnect ( startAction, SIGNAL ( triggered() ), this, SLOT ( pauseGame() ) );
	connect ( startAction, SIGNAL ( triggered() ), this, SLOT ( startGame() ) );
}

void QWorld::stopGame()
{
	pauseGame();
	game -> reset();
}
